package com.gobang.api;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.gobang.game.MatchResponse;
import com.gobang.game.MatchResqest;
import com.gobang.game.Matcher;
import com.gobang.game.OnlineUserManager;
import com.gobang.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
//通过这个类来处理匹配功能的websocket请求
@Component
public class MatchAPI extends TextWebSocketHandler {
    @Autowired
    private OnlineUserManager onlineUserManager;
    private ObjectMapper objectMapper = new ObjectMapper();
    @Autowired
    private Matcher matcher;
    /**
     * 玩家上线，加入OnlineUserManager
     *
     * @param session
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        try {

            //1、先获取到当前用户信息
            //  首先，在UserAPI的login方法中有的session.setAttribute("user", user);
            //  相当于在Http登录逻辑中，往HttpSession中存入了User数据
            //  然后，来自WebSocketConfig的.addInterceptors(new HttpSessionHandshakeInterceptor()
            //  相当于把HttpSession中的Attribute拿到WebsocketSession中
            //  最后，就实现了在WebSocketSession中把之前HttpSession里存的User对象拿到
            User user = (User) session.getAttributes().get("user");
            //2.检查玩家的登录状态
            if (user == null) {
                // 拿不到⽤⼾的登录信息, 说明玩家未登录就进⼊游戏⼤厅了.
                // 则返回错误信息并关闭连接
                MatchResponse response = new MatchResponse();
                response.setOk(false);
                response.setReason("玩家尚未登录!");
                session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
                return;
            }
            //3.判定当前用户是否已经登陆过（已经是在线状态），如果已在线，就不该继续进行后续逻辑
            //防止用户多浏览器登录同一账号，这样会导致，前一个登录的id-session键值名存实亡，只能用后一个登录的(虽然同一id)
           WebSocketSession temSession = onlineUserManager.getFromGameHall(user.getUserId());
            if(temSession != null){
                //当前这个用户已经登录了
                //这个情况要告知客户端，这里重复登录
                MatchResponse response = new MatchResponse();
                response.setOk(true);
                response.setReason("当前禁止多开");
                System.out.println("禁止多开");
                response.setMessage("repeatConnection");
                session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
                //session.close();
                return;
            }
            //4.拿到身份信息之后，就可以把玩家设置成在线状态
            onlineUserManager.enterGanmeHall(user.getUserId(), session);
            System.out.println("玩家" + user.getUsername() + "进入游戏大厅");
        } catch (NullPointerException e) {
            System.out.println("[MatchAPI.afterConnectionError]当前用户未登录");
            //出现空指针异常，说明当前用户的身份是空，用户未登录
            //把当前用户尚未登录这个信息给返回去
//            e.printStackTrace();
//            MatchResponse response = new MatchResponse();
//            response.setOk(false);
//            response.setReason("您尚未登录,不能进行匹配");
//            //先通过ObjectMapper把MatchResponse对象转成JSON字符串
//            // 然后再包装上一层TextMessage,再传输
//            // new TextMessage()表示一个文本格式的websocket的数据包
//            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
    }

    /**
     * 现处理开始匹配请求和处理停止匹配请求
     *
     * @param session
     * @param message
     * @throws Exception
     */
    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage message) throws Exception {
        //实现处理开始匹配请求和处理停止匹配请求
        User user = (User)session.getAttributes().get("user");
        //获取到客户端给服务器发送的数据
        String payload = (String) message.getPayload();
        //当前这个数据载荷是一个JSON格式的字符串，就需要把它转成java对象，MatchRequest
        MatchResqest resqest = objectMapper.readValue(payload,MatchResqest.class);
        MatchResponse response = new MatchResponse();
        if(resqest.getMessage().equals("startMatch")){
            //进入匹配队列
            //把当前用户加进去队列
            matcher.add(user);
            //把玩家信息放进匹配队列之后，就可以返回一个相应给客户端
            response.setOk(true);
            response.setMessage("startMatch");
        }else if(resqest.getMessage().equals("stopMatch")){
            //退出匹配队列
            //把当前用户从队列退出去
            matcher.remove(user);
            //移除之后，可以返回一个响应给客户端
            response.setOk(true);
            response.setMessage("stopMatch");
        }else {
            response.setOk(false);
            response.setReason("非法匹配请求");
        }

        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));


    }

    /**
     * 玩家下线，从OnlineUserManager中删除
     *
     * @param session
     * @param exception
     * @throws Exception
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        try {
            User user = (User) session.getAttributes().get("user");
            //防止多开的情况下，关闭用户一刀切
            WebSocketSession tempSession = onlineUserManager.getFromGameHall(user.getUserId()); //这个是去拿之前的id session
            if(tempSession == session){
                onlineUserManager.exitGameHall(user.getUserId());
                System.out.println("玩家" + user.getUsername() + "退出游戏大厅");
            }
            //如果玩家在匹配过程中，而websocket连接断开，就应该移除匹配
            matcher.remove(user);
        } catch (NullPointerException e) {
            System.out.println("[MatchAPI.afterConnectionError]当前用户未登录");

            //连接关闭之后，不应该发送消息给客户端
//            e.printStackTrace();
//            MatchResponse response = new MatchResponse();
//            response.setOk(false);
//            response.setReason("您尚未登录,不能进行匹配");
//            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
    }

    /**
     * 玩家下线，从OnlineUserManager中删除
     *
     * @param session
     * @param status
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        try {
            User user = (User) session.getAttributes().get("user");
            //当出现多开的情况时，afterConnectionEstablished方法中的session.close();会执行当前方法
            //但是，多开的id是一样的，如果不处理，会关闭此id所有账号，不符合实际情况
            //所以，关闭的时候要判断，当前要下线的用户是不是当前session的用户,这样判断的不止id，还有用户信息
            WebSocketSession tempSession = onlineUserManager.getFromGameHall(user.getUserId());
            if(tempSession == session){
                onlineUserManager.exitGameHall(user.getUserId());
            }
            //如果玩家在匹配过程中，而websocket连接断开，就应该移除匹配
            matcher.remove(user);
            System.out.println("玩家" + user.getUsername() + "退出游戏大厅");
        } catch (NullPointerException e) {
            System.out.println("[MatchAPI.afterConnectionClosed]当前用户未登录");

            //连接关闭之后，不应该发送消息给客户端
            //e.printStackTrace();
//            MatchResponse response = new MatchResponse();
//            response.setOk(false);
//            response.setReason("您尚未登录,不能进行匹配");
//            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }

    }
}